/*-------------------------------------------------------------------------
 *
 * extensible.c
 *	  对可扩展节点类型的支持
 *
 * 可加载模块可以使用此文件中的例程定义实际上是新类型的
 * 节点。所有这些节点都标记为 T_ExtensibleNode，extnodename 字段
 * 使其区分特定类型。使用 RegisterExtensibleNodeMethods 注册新的
 * 可扩展节点类型，使用 GetExtensibleNodeMethods 获取有关先前注
 * 册的可扩展节点类型的信息。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  src/backend/nodes/extensible.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "nodes/extensible.h"
#include "utils/hsearch.h"

static HTAB *extensible_node_methods = NULL;
static HTAB *custom_scan_methods = NULL;

typedef struct
{
	char		extnodename[EXTNODENAME_MAX_LEN];
	const void *extnodemethods;
} ExtensibleNodeEntry;

/*
 * 一个内部函数，用于注册一个新的回调结构
 */
static void fc_RegisterExtensibleNodeEntry(HTAB **fc_p_htable, const char *fc_htable_label,
							const char *fc_extnodename,
							const void *fc_extnodemethods)
{
	ExtensibleNodeEntry *fc_entry;
	bool		fc_found;

	if (*fc_p_htable == NULL)
	{
		HASHCTL		fc_ctl;

		fc_ctl.keysize = EXTNODENAME_MAX_LEN;
		fc_ctl.entrysize = sizeof(ExtensibleNodeEntry);

		*fc_p_htable = hash_create(fc_htable_label, 100, &fc_ctl,
								HASH_ELEM | HASH_STRINGS);
	}

	if (strlen(fc_extnodename) >= EXTNODENAME_MAX_LEN)
		elog(ERROR, "extensible node name is too long");

	fc_entry = (ExtensibleNodeEntry *) hash_search(*fc_p_htable,
												fc_extnodename,
												HASH_ENTER, &fc_found);
	if (fc_found)
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_OBJECT),
				 errmsg("extensible node type \"%s\" already exists",
						fc_extnodename)));

	fc_entry->extnodemethods = fc_extnodemethods;
}

/*
 * 注册一种新的可扩展节点类型。
 */
void RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *fc_methods)
{
	fc_RegisterExtensibleNodeEntry(&extensible_node_methods,
								"Extensible Node Methods",
								fc_methods->extnodename,
								fc_methods);
}

/*
 * 注册一种新的自定义扫描节点类型
 */
void RegisterCustomScanMethods(const CustomScanMethods *fc_methods)
{
	fc_RegisterExtensibleNodeEntry(&custom_scan_methods,
								"Custom Scan Methods",
								fc_methods->CustomName,
								fc_methods);
}

/*
 * 一个内部例程，用于通过给定的标识符获取 ExtensibleNodeEntry
 */
static const void *
fc_GetExtensibleNodeEntry(HTAB *fc_htable, const char *fc_extnodename, bool fc_missing_ok)
{
	ExtensibleNodeEntry *fc_entry = NULL;

	if (fc_htable != NULL)
		fc_entry = (ExtensibleNodeEntry *) hash_search(fc_htable,
													fc_extnodename,
													HASH_FIND, NULL);
	if (!fc_entry)
	{
		if (fc_missing_ok)
			return NULL;
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("ExtensibleNodeMethods \"%s\" was not registered",
						fc_extnodename)));
#ifdef FDD //cppcheck
		return NULL;//cppcheck
#endif
	}

	return fc_entry->extnodemethods;
}

/*
 * 获取给定类型的可扩展节点的方法。
 */
const ExtensibleNodeMethods *
GetExtensibleNodeMethods(const char *fc_extnodename, bool fc_missing_ok)
{
	return (const ExtensibleNodeMethods *)
		fc_GetExtensibleNodeEntry(extensible_node_methods,
							   fc_extnodename,
							   fc_missing_ok);
}

/*
 * 获取给定名称的 CustomScanMethods 的方法
 */
const CustomScanMethods *
GetCustomScanMethods(const char *fc_CustomName, bool fc_missing_ok)
{
	return (const CustomScanMethods *)
		fc_GetExtensibleNodeEntry(custom_scan_methods,
							   fc_CustomName,
							   fc_missing_ok);
}
